#include <ff_utils.h>

using namespace feifei;

typedef struct args_struct
{
	int* pCnt;
	Mutex mtx;
	Event evt;
}t_args;

// thread param test
THREAD_CALL thread1(void* pArgs)
{
	printf("[t1]: enter thread1...\n");
	t_args args = *(t_args*)pArgs;

	int counter;
	counter = *(args.pCnt);
	printf("[t1]: counter = %d\n", counter);
	ffSleepSec(4);
	counter = *(args.pCnt);
	printf("[t1]: counter = %d\n", counter);

	printf("[t1]: exit thread1.\n");
}
THREAD_CALL thread2(void* pArgs)
{
	printf("[t1]: enter thread1...\n");
	t_args args = *(t_args*)pArgs;

	int *pCnt = args.pCnt;
	printf("[t2]: counter = %d\n", *pCnt);
	while(*pCnt < 10)
	{
		*pCnt = *pCnt + 1;
		printf("[t2]: counter = %d\n", *pCnt);
		ffSleepSec(0.2);
	}

	printf("[t2]: exit thread2.\n");
}

// mutex test
THREAD_CALL thread3(void* pArgs)
{
	printf("[t3]: enter thread3...\n");
	t_args args = *(t_args*)pArgs;
	int* pCnt = args.pCnt;
	Mutex mtx = args.mtx;

	for (uint32_t i = 0; i < 1000; i++)
	{
		MutexLock(mtx);
		*pCnt = *pCnt + 1;
		MutexUnlock(mtx);
		ffSleepMilliSec(0.1);
	}

	printf("[t3]: counter = %d\n", *pCnt);
	printf("[t3]: exit thread3.\n");
}
THREAD_CALL thread4(void* pArgs)
{
	printf("[t4]: enter thread4...\n");
	t_args args = *(t_args*)pArgs;
	int* pCnt = args.pCnt;
	Mutex mtx = args.mtx;

	for (uint32_t i = 0; i < 1000; i++)
	{
		MutexLock(mtx);
		*pCnt = *pCnt + 1;
		MutexUnlock(mtx);
		ffSleepMilliSec(0.1);
	}

	printf("[t4]: counter = %d\n", *pCnt);
	printf("[t4]: exit thread4.\n");
}

// event test
THREAD_CALL thread5(void* pArgs)
{
	printf("[t5]: enter thread5...\n");
	t_args args = *(t_args*)pArgs;
	int* pCnt = args.pCnt;
	Mutex mtx = args.mtx;
	Event evt = args.evt;

	EventWaitFor(evt); // wait for ever
	while (EventWaitFor(evt, 100) == false)
	{
		*pCnt = *pCnt + 1;
		//printf("[t5] cnt ++ \n");
	}

	printf("[t5]: exit thread5.\n");
}
THREAD_CALL thread6(void* pArgs)
{
	printf("[t6]: enter thread6...\n");
	t_args args = *(t_args*)pArgs;
	int* pCnt = args.pCnt;
	Mutex mtx = args.mtx;
	Event evt = args.evt;

	ffSleepSec(1.5);
	EventSet(evt);
	ffSleepMilliSec(1000);
	EventSet(evt);

	printf("[t6]: exit thread6.\n");
}

int main()
{
	int errorCount = 0;

	t_args args;		
	t_args* pArgs = &args;
	int counter = 0;	
	int* pCounter = &counter;
	Mutex mtx = MutexCreate();
	Event evt = EventCreate();
	args.mtx = mtx;
	args.evt = evt;
	args.pCnt = pCounter;
	Thread tid_list[2];

	// test thread create and destory
	counter = 0;
	Thread tid1,tid2;
	printf("[main]: create threads1/2...\n");
	tid1 = ThreadCreate(thread1, pArgs);
	tid2 = ThreadCreate(thread2, pArgs);
	printf("[main]: tid1 = %lld, tid2 = %lld\n", tid1, tid2);
	printf("[main]: wait for thread1...\n");
	ThreadWaitFor(tid1);
	printf("[main]: wait for thread2...\n");
	ThreadWaitFor(tid2);
	printf("[main]: destory thread1/2.\n");
	ThreadDestory(tid1);
	ThreadDestory(tid2);
	printf("[main]: counter = %d\n", counter);
	if (counter != 10) errorCount++;

	// test mutex
	counter = 0;
	Thread tid3, tid4;
	printf("[main]: create threads3/4...\n");
	tid3 = ThreadCreate(thread3, pArgs);
	tid4 = ThreadCreate(thread4, pArgs);
	tid_list[0] = tid3; tid_list[1] = tid4;
	printf("[main]: tid3 = %lld, tid4 = %lld\n", tid3, tid4);
	printf("[main]: wait for all thread...\n");
	ThreadsWaitForAll(&tid_list[0], 2);
	printf("[main]: destory thread3/4.\n");
	ThreadDestory(tid3);
	ThreadDestory(tid4);
	printf("[main]: counter = %d\n", counter);
	if (counter != 2000) errorCount++;

	// test event
	counter = 0;
	Thread tid5, tid6;
	printf("[main]: create threads5/6...\n");
	tid5 = ThreadCreate(thread5, pArgs);
	tid6 = ThreadCreate(thread6, pArgs);
	printf("[main]: tid5 = %lld, tid6 = %lld\n", tid5, tid6);
	printf("[main]: wait for thread5/6.\n");
	ThreadWaitFor(tid5);
	ThreadWaitFor(tid6);
	printf("[main]: destory thread5/6.\n");
	ThreadDestory(tid5);
	ThreadDestory(tid6);
	printf("[main]: counter = %d\n", counter);
	if (counter != 9) errorCount++;

	// clear
	EventDestroy(evt);
	MutexDestroy(mtx);
	printf("[main]: error count = %d\n", errorCount);
	return errorCount;
}
